ElasticSearch 如何像 MySQL 一样做多表联合查询? 您所在的位置:网站首页 redis search 支持 关联查询吗 ElasticSearch 如何像 MySQL 一样做多表联合查询?

ElasticSearch 如何像 MySQL 一样做多表联合查询?

2024-06-17 18:38| 来源: 网络整理| 查看: 265

关系型数据库中有表的关联关系,在 es 中,我们也有类似的需求,例如订单表和商品表,在 es 中,这样的一对多一般来说有两种方式:

嵌套文档(nested)

父子文档

18.1 嵌套文档

假设:有一个电影文档,每个电影都有演员信息:

PUT movies{ "mappings": { "properties": { "actors":{ "type": "nested" } } }}PUT movies/_doc/1{ "name":"霸王别姬", "actors":[ { "name":"张国荣", "gender":"男" }, { "name":"巩俐", "gender":"女" } ]}

注意 actors 类型要是 nested,具体原因参考 10.2.3 小节。

缺点

查看文档数量:

GET _cat/indices?v

查看结果如下:

image-20201119162958456

这是因为 nested 文档在 es 内部其实也是独立的 lucene 文档,只是在我们查询的时候,es 内部帮我们做了 join 处理,所以最终看起来就像一个独立文档一样。因此这种方案性能并不是特别好。

18.2 嵌套查询

这个用来查询嵌套文档:

GET movies/_search{ "query": { "nested": { "path": "actors", "query": { "bool": { "must": [ { "match": { "actors.name": "张国荣" } }, { "match": { "actors.gender": "男" } } ] } } } }} 18.3 父子文档

相比于嵌套文档,父子文档主要有如下优势:

更新父文档时,不会重新索引子文档

创建、修改或者删除子文档时,不会影响父文档或者其他的子文档。

子文档可以作为搜索结果独立返回。

例如学生和班级的关系:

PUT stu_class{ "mappings": { "properties": { "name":{ "type": "keyword" }, "s_c":{ "type": "join", "relations":{ "class":"student" } } } }}

s_c

表示父子文档关系的名字,可以自定义。join 表示这是一个父子文档。relations 里边,class 这个位置是 parent,student 这个位置是 child。

接下来,插入两个父文档:

PUT stu_class/_doc/1{ "name":"一班", "s_c":{ "name":"class" }}PUT stu_class/_doc/2{ "name":"二班", "s_c":{ "name":"class" }}

再来添加三个子文档:

PUT stu_class/_doc/3?routing=1{ "name":"zhangsan", "s_c":{ "name":"student", "parent":1 }}PUT stu_class/_doc/4?routing=1{ "name":"lisi", "s_c":{ "name":"student", "parent":1 }}PUT stu_class/_doc/5?routing=2{ "name":"wangwu", "s_c":{ "name":"student", "parent":2 }}

首先大家可以看到,子文档都是独立的文档。特别需要注意的地方是,子文档需要和父文档在同一个分片上,所以 routing 关键字的值为父文档的 id。另外,name 属性表明这是一个子文档。

父子文档需要注意的地方:

每个索引只能定义一个 join filed

父子文档需要在同一个分片上(查询,修改需要routing)

可以向一个已经存在的 join filed 上新增关系

18.4 has_child query

通过子文档查询父文档使用 has_child

query。

GET stu_class/_search{ "query": { "has_child": { "type": "student", "query": { "match": { "name": "wangwu" } } } }}

查询 wangwu 所属的班级。

18.5 has_parent query

通过父文档查询子文档:

GET stu_class/_search{ "query": { "has_parent": { "parent_type": "class", "query": { "match": { "name": "二班" } } } }}

查询二班的学生。但是大家注意,这种查询没有评分。

可以使用 parent id 查询子文档:

GET stu_class/_search{ "query": { "parent_id":{ "type":"student", "id":1 } }}

通过 parent id 查询,默认情况下使用相关性计算分数。

18.6 小结

整体上来说:

普通子对象实现一对多,会损失子文档的边界,子对象之间的属性关系丢失。

nested 可以解决第 1 点的问题,但是 nested 有两个缺点:更新主文档的时候要全部更新,不支持子文档属于多个主文档。

父子文档解决 1、2 点的问题,但是它主要适用于写多读少的场景。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有